#include "processor.h"


////////////////////////////////////////////////////////////////////////////////////
// The Rename Stage has two sub-stages:
// rename1: Get the next rename bundle from the FQ.
// rename2: Rename the current rename bundle.
////////////////////////////////////////////////////////////////////////////////////

void processor::rename1() {
	unsigned int i, index;
	unsigned int current_trace_width;

	////////////////////////////////////////////////////////////////////////////////////
	// Try to get the next rename bundle.
	// Two conditions might prevent getting the next rename bundle, either:
	// (1) The current rename bundle is stalled in rename2.
	// (2) The FQ does not have enough instructions for a full rename bundle.
	////////////////////////////////////////////////////////////////////////////////////

	// Check the first condition. Is the current rename bundle stalled, preventing
	// insertion of the next rename bundle? Check whether or not the pipeline register
	// between rename1 and rename2 still has a rename bundle.

	if (RENAME2[0].valid)	// The current rename bundle is stalled.
		return;

	// Check the second condition. Does the FQ have enough instructions for a full
	// rename bundle?

	index = FQ.read_head_index();
	if (index == -1)
		return;

	current_trace_width = PAY.trace_buf[PAY.buf[index].trace_ID].length;

	//assert(current_trace_width == PAY.buf[index].trace_length);

	if (!FQ.bundle_ready(current_trace_width))
		return;

	// Get the next rename bundle:
	// The FQ has a rename bundle and there is space for it in the Rename Stage.
	for (i = 0; i < current_trace_width; i++) {
		RENAME2[i].valid = true;
		index = FQ.pop();
		RENAME2[i].index = index;
		PAY.buf[index].trace_length = current_trace_width;
	}
}

void processor::rename2() {
	unsigned int i;
	unsigned int index, *indices;
	unsigned int current_trace_width;

	unsigned int first_id;


	// Stall the rename2 sub-stage if either:
	// (1) There isn't a current rename bundle.
	// (2) The Dispatch Stage is stalled.
	// (3) There aren't enough rename resources for the current rename bundle.

	if (!RENAME2[0].valid ||	// First stall condition: There isn't a current rename bundle.
			DISPATCH[0].valid)	// Second stall condition: The Dispatch Stage is stalled.
		return;

	// Third stall condition: There aren't enough rename resources for the current rename bundle.

	unsigned int numCheckPoints = 1, numIntDestRegisters = 0, numFPDestRegisters = 0;

	index = RENAME2[0].index;
	current_trace_width =  PAY.trace_buf[PAY.buf[index].trace_ID].length;

	assert(current_trace_width == PAY.buf[index].trace_length);

	first_id = PAY.buf[index].trace_ID;
	indices = (unsigned int *) malloc (sizeof(unsigned int) * current_trace_width);

	for (i = 0; i < current_trace_width; i++) {
		assert(RENAME2[i].valid);
		index = RENAME2[i].index;
		indices[i] = index;


		assert(first_id == PAY.buf[index].trace_ID);
	}

	// FIX_ME #1
	// Count the number of instructions in the rename bundle that need a checkpoint (most branches).
	// Count the number of instructions in the rename bundle that have an integer destination register.
	// Count the number of instructions in the rename bundle that have a floating-point destination register.
	// With these counts, you will be able to query the integer and floating-point renamers for resource availability
	// (checkpoints and physical registers).
	//
	// Tips:
	// 1. The loop construct, for iterating through all instructions in the rename bundle (0 to dispatch_width),
	//    is already provided for you, above. Note that this comment is within the loop.
	// 2. At this point of the code, 'index' is the instruction's index into PAY.buf[] (payload).
	// 3. The instruction's payload has all the information you need to count resource needs.
	//    There is a flag in the instruction's payload that *directly* tells you if this instruction needs a checkpoint.
	//    Other fields indicate whether or not the instruction has a destination register and its type.

	// Check point per trace No need to check individually.
	//      if(PAY.buf[index].checkpoint)
	//    	  numCheckPoints ++;

	preRenamer(indices, current_trace_width);

	for (i = 0; i < current_trace_width; i++) {
		assert(RENAME2[i].valid);
		index = RENAME2[i].index;


		if (PAY.buf[index].C_valid && (PAY.buf[index].C_hierarchy & GLOBAL_REGISTER))
		{
			if (PAY.buf[index].C_int)
				numIntDestRegisters ++;
			else
				numFPDestRegisters ++;
		}
	}




	// FIX_ME #2
	// Check if the Rename2 Stage must stall due to any of the following conditions:
	// * Not enough free checkpoints.
	// * Not enough free integer physical registers.
	// * Not enough free floating-point physical registers.
	//
	// If there are not enough resources for the *whole* rename bundle, then stall the Rename2 Stage.
	// Stalling is achieved by returning from this function ('return').
	// If there are enough resources for the *whole* rename bundle, then do not stall the Rename2 Stage.
	// This is achieved by doing nothing and proceeding to the next statements.
	//
	// Tips:
	// 1. Check the stall_branch() functions for both the integer and floating-point renamers.
	//    Assert that they return the same result, since they have the same number of checkpoints.
	// 2. Check the stall_reg() functions for both the integer and floating-point renamers,
	//    passing in the correct argument to each.
	// 3. If you need to stall, you do it by hard exiting this function with 'return'. Otherwise do nothing.

	assert(REN_INT->stall_branch(numCheckPoints) == REN_FP->stall_branch(numCheckPoints));

	if (REN_INT->stall_branch(numCheckPoints))
		return;

	if (REN_INT->stall_reg(numIntDestRegisters))
		return;

	if (REN_FP->stall_reg(numFPDestRegisters))
		return;

	unsigned long long GBM = REN_INT->get_branch_mask();

	//
	// Sufficient resources are available to rename the rename bundle.
	//
	for (i = 0; i < current_trace_width; i++) {
		assert(RENAME2[i].valid);
		index = RENAME2[i].index;

		// FIX_ME #3
		// Rename source registers (first) and destination register (second).
		//
		// Tips:
		// 1. At this point of the code, 'index' is the instruction's index into PAY.buf[] (payload).
		// 2. The instruction's payload has all the information you need to rename registers, if they exist. In particular:
		//    * whether or not the instruction has a first source register, its logical register number, and its type
		//    * whether or not the instruction has a second source register, its logical register number, and its type
		//    * whether or not the instruction has a destination register, its logical register number, and its type
		// 3. When you rename a logical register to a physical register, remember to *update* the instruction's payload with the physical register specifier,
		//    so that the physical register specifier can be used in subsequent pipeline stages.

		//Source A:

		if (PAY.buf[index].A_valid && (PAY.buf[index].A_hierarchy & GLOBAL_REGISTER))
		{
			if (PAY.buf[index].A_int)
				PAY.buf[index].A_phys_reg = REN_INT->rename_rsrc(PAY.buf[index].A_log_reg);
			else
				PAY.buf[index].A_phys_reg = REN_FP->rename_rsrc(PAY.buf[index].A_log_reg);
		}

		//Source B:
		if (PAY.buf[index].B_valid && (PAY.buf[index].B_hierarchy & GLOBAL_REGISTER))
		{
			if (PAY.buf[index].B_int)
				PAY.buf[index].B_phys_reg = REN_INT->rename_rsrc(PAY.buf[index].B_log_reg);
			else
				PAY.buf[index].B_phys_reg = REN_FP->rename_rsrc(PAY.buf[index].B_log_reg);
		}

		//Destination C:
		if (PAY.buf[index].C_valid && (PAY.buf[index].C_hierarchy & GLOBAL_REGISTER))
		{
			if (PAY.buf[index].C_int)
			{
				PAY.buf[index].C_phys_reg = REN_INT->rename_rdst(PAY.buf[index].C_log_reg);
				//REN_INT->clear_ready(PAY.buf[index].C_phys_reg);
			}
			else
			{
				PAY.buf[index].C_phys_reg = REN_FP->rename_rdst(PAY.buf[index].C_log_reg);
				//REN_FP->clear_ready(PAY.buf[index].C_phys_reg);
			}
		}

		// FIX_ME #4
		// Get the instruction's branch mask.
		//
		// Tips:
		// 1. Every instruction gets a branch_mask. An instruction needs to know which branches it depends on, for possible squashing.
		// 2. The branch_mask is not held in the instruction's PAY.buf[] entry. Rather, it explicitly moves with the instruction
		//    from one pipeline stage to the next. Normally the branch_mask would be wires at this point in the logic but since we
		//    don't have wires place it temporarily in the RENAME2[] pipeline register alongside the instruction, until it advances
		//    to the DISPATCH[] pipeline register. The required left-hand side of the assignment statement is already provided for you below:
		//    RENAME2[i].branch_mask = ??;
		// 3. Both renamers should return the same branch_mask because their checkpoints are managed identically.
		//    You should assert this: get branch_mask's from both renamers and assert they are identical.

		RENAME2[i].branch_mask = GBM;


		assert (REN_INT->get_branch_mask() == REN_FP->get_branch_mask());

		// FIX_ME #5
		// If this instruction requires a checkpoint (most branches), then create a checkpoint.
		//
		// Tips:
		// 1. At this point of the code, 'index' is the instruction's index into PAY.buf[] (payload).
		// 2. There is a flag in the instruction's payload that *directly* tells you if this instruction needs a checkpoint.
		// 3. If a checkpoint is needed, you must create a checkpoint in both the integer and floating-point renamers.
		//    Assert that they return the same branch ID, since their checkpoints are managed identically.
		// 4. If you create a checkpoint, remember to *update* the instruction's payload with its branch ID
		//    so that the branch ID can be used in subsequent pipeline stages.


		//      if (PAY.buf[index].checkpoint)
		//      {
		//    	  unsigned int intCP = REN_INT->checkpoint();
		//    	  unsigned int fpCP = REN_FP->checkpoint();
		//
		//
		//    	  assert(intCP == fpCP);
		//    	  PAY.buf[index].branch_ID = intCP;
		//
		//      }


	}

	//Checkpoint mechanism
	unsigned int intCP;
	unsigned int fpCP;

	if(RENAME2[0].valid)
	{
		intCP = REN_INT->checkpoint();
		fpCP = REN_FP->checkpoint();

		assert(intCP == fpCP);

	}
	for( i=0; i<current_trace_width; i++)
	{
		assert(RENAME2[i].valid);
		index = RENAME2[i].index;
		PAY.buf[index].branch_ID = intCP;
	}
	//
	// Transfer the rename bundle from the Rename Stage to the Dispatch Stage.
	//
	for (i = 0; i < current_trace_width; i++) {
		assert(RENAME2[i].valid && !DISPATCH[i].valid);
		RENAME2[i].valid = false;
		DISPATCH[i].valid = true;
		DISPATCH[i].index = RENAME2[i].index;
		DISPATCH[i].branch_mask = RENAME2[i].branch_mask;
	}
}
